#include "GLConsole.h"

namespace mp_gl
{
	GLConsole::GLConsole()
		:Drawable()
	{
		m_window = NULL;
		m_directChar = NULL;

		//No font loaded, set to null
		m_font = new GLBitmapFont();


		//Setup input line
		m_input = new string();

		//Setup output lines
		m_output = new string*[MPCON_OUTPUT_MAX_LINES];
		for(int i = 0; i < MPCON_OUTPUT_MAX_LINES; i++)
		{
			m_output[i] = NULL;
		}
		m_outputLineCount = 0;

		//Test Display
		m_output[m_outputLineCount] = new string();
		m_output[m_outputLineCount++]->append("====== Basic Console ======");
		m_input = new string();
		
	}

	GLConsole::~GLConsole()
	{
		//Cleanup the console text arrays
		delete m_input;
		for(int i = 0; i < MPCON_OUTPUT_MAX_LINES; i++)
			if ( m_output[i] != NULL)
				delete m_output[i];
		delete [] m_output;
	}


	void GLConsole::Initialize()
	{
		m_btnConEvent.reset(new GLKeyboardEvent());
		((GLKeyboardEvent*)&*m_btnConEvent)->SetKey(GLFW_KEY_TAB);
		m_inputManager->GetInputEventCollection()->push_back(m_btnConEvent);

		m_btnBackspaceEvent.reset(new GLKeyboardEvent());
		((GLKeyboardEvent*)&*m_btnBackspaceEvent)->SetKey(GLFW_KEY_BACKSPACE);
		m_inputManager->GetInputEventCollection()->push_back(m_btnBackspaceEvent);

		m_btnEnterEvent.reset(new GLKeyboardEvent());
		((GLKeyboardEvent*)&*m_btnEnterEvent)->SetKey(GLFW_KEY_ENTER);
		m_inputManager->GetInputEventCollection()->push_back(m_btnEnterEvent);

		m_directChar.reset(new GLDirectKeyboardInput());
		m_inputManager->AddDirectKeyboardListener(&*m_directChar);
	}

	void GLConsole::LoadContent()
	{
		//Load the consoles bitmap font
		m_font->Load(m_fontDir);
		m_font->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
	}

	void GLConsole::Update()
	{
		//if(m_errorEvent != NULL)
			//if (m_errorEvent->IsTriggered() )
				//WriteLine(m_errorEvent->GetErrorMessage());

		//Open or close the console
		if ( m_btnConEvent != NULL )
			if ( m_btnConEvent->IsTriggered() )
			{
				m_visible = !m_visible;
				m_directChar->flush();
				m_btnBackspaceEvent->Reset();
				m_btnEnterEvent->Reset();
			}

		//Read into input, if visible
		if ( m_visible )
		{

			if(m_directChar != NULL)
			{
				//If backspace pressed
				if ( m_btnBackspaceEvent->IsTriggered() )
				{
					if ( m_input->length() > 0 )
						m_input->pop_back();
				}
				//If reading normal characters into input
				else if ( m_directChar->IsInputAvailable() )
				{
					char chr = m_directChar->read();
					if ( m_input->length() < MPCON_LINE_MAX )
					{
						m_input->push_back(chr);
					}
				
				}
				//If enter pressed
				else if ( m_btnEnterEvent->IsTriggered() )
				{
					ProcessInput();
				}
			}
		}
	}

	void GLConsole::ProcessInput()
	{
		WriteLine(m_input);
		m_input->clear();
	}

	void GLConsole::WriteLine(const string line)
	{
		if ( m_outputLineCount < MPCON_OUTPUT_MAX_LINES )
		{
			m_output[m_outputLineCount] = new string();
			m_output[m_outputLineCount++]->append(line);
		}
	}
	
	void GLConsole::WriteLine(const string* const line)
	{
		if ( m_outputLineCount < MPCON_OUTPUT_MAX_LINES )
		{
			m_output[m_outputLineCount] = new string();
			m_output[m_outputLineCount++]->append(*line);
		}
	}

	void GLConsole::Draw()
	{
		if ( m_visible )
		{
			int width;
			int height;
			glfwGetWindowSize(m_window, &width, &height);

			Area outputArea = Area(0,width, m_font->GetHeight()*2, height);
			Area inputArea = Area(0, width ,0, m_font->GetHeight() );

			SetglOrtho(0, width, 0, height, 1, -1);
			BindFonts();
			DrawOutputText(outputArea);
			DrawInputText(inputArea);
		}
	}

	void GLConsole::SetglOrtho(
		double left, double right, 
		double bottom, double top, 
		double zNear, double zFar)
	{
		//Setup view matrix for console to draw
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(left,right,bottom,top,zNear,zFar);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glEnable(GL_TEXTURE_2D);
	}

	void GLConsole::DrawOutputText(const Area area)
	{
		int lineIndex;
		int yOffset = area.m_yMax - m_font->GetHeight();

		//Calculate max lines drawable
		int maxLines = (int)(	
			(area.m_yMax - area.m_yMin - m_font->GetHeight()) / 
				 m_font->GetHeight() );

		//Calculate the starting output line index
		if ( m_outputLineCount > maxLines )
			lineIndex = m_outputLineCount - maxLines;
		else
			lineIndex = 0;

		//Calculate safe number of lines to draw
		int linesToPrint;
		if ( (maxLines ) >= MPCON_OUTPUT_MAX_LINES )
			linesToPrint = MPCON_OUTPUT_MAX_LINES;
		else
			linesToPrint = maxLines; 

		//Draw the lines
		for(int i = 0; i < linesToPrint; i++)
		{
			if ( m_output[i+lineIndex] == NULL)
				break;
			m_font->Print(
				m_output[i+lineIndex]->c_str(),
				area.m_xMin, yOffset);
			yOffset -= m_font->GetHeight();
		}
	}

	void GLConsole::DrawInputText(const Area area)
	{
		m_font->Print(
			m_input->c_str(), area.m_xMin, area.m_yMin);
	}

	
	void GLConsole::DrawOutputLine(const Area area, const unsigned int index)
	{

	}

	void GLConsole::SetFont(char* fileDir)
	{
		//Set the font location prior to loading
		m_fontDir = fileDir;
	}

}